#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "Common/Utils.h"

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

// 声明一些全局数据
#define numVAOs 1
GLuint renderingProgram;
GLuint vao[numVAOs];
float offsetX = 0.0f;

void Init(GLFWwindow* window);
void Update(GLFWwindow* window, double currentTime);
void Render();

int main()
{
    // 初始化GLFW
    if(!glfwInit())
    {
        exit(EXIT_FAILURE);
    }

    // 设置window的各种状态
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    // 创建GLFWwindow
    GLFWwindow* window = glfwCreateWindow(800, 600, "Test", nullptr, nullptr);
    if(!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    // 初始化上下文
    glfwMakeContextCurrent(window);

    // 初始化glad
    if(!gladLoadGLLoader(GLADloadproc(glfwGetProcAddress)))
    {
        glfwDestroyWindow(window);
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    // 设定垂直同步
    glfwSwapInterval(1);

    Init(window);

    // 主循环
    while(!glfwWindowShouldClose(window))
    {
        // 逻辑更新
        Update(window, glfwGetTime());
        // 渲染更新
        Render();
        // 交换缓冲帧
        glfwSwapBuffers(window);
        // poll事件
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();

    exit(EXIT_SUCCESS);
}

void Init(GLFWwindow* window)
{
    renderingProgram = Utils::CreateShaderProgram("../../Test/vertShader.glsl",
                                                  "../../Test/fragShader.glsl");
    glGenVertexArrays(numVAOs, vao);
    glBindVertexArray(vao[0]);
}

void Update(GLFWwindow* window, double currentTime)
{
    offsetX = sinf(currentTime);
}

void Render()
{
    // 为所有的color buffers指定clear颜色
    glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    // clear所有的color buffers和depth buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 将program里包含的编译好的shader上载到GPU管线去
    // 注意，这个时候并不会发生shader invocation（不会运行shader）
    glUseProgram(renderingProgram);
    glProgramUniform1f(renderingProgram, glGetUniformLocation(renderingProgram, "offsetX"), offsetX);
    // 这里开始执行GPU管线
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glProgramUniform1f(renderingProgram, glGetUniformLocation(renderingProgram, "offsetX"), 0.5f);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    // 检查运行时shader错误
    Utils::CheckOpenGLError();
}